#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

struct list
{
  struct list* next;
  int data;
};

struct list* head;
pthread_mutex_t lock;
pthread_cond_t cond;

void* producer(void*);
void* consumer(void*);

int main(int argc,char** argv)
{
  srand(time(NULL));
  head = malloc(sizeof(struct list));
  head->next = NULL;
  if(head == NULL)
  {
    fprintf(stderr,"head malloc is fail\n");
    exit(-1);
  }
  int ret;
  ret = pthread_mutex_init(&lock,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_int is fail %s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_cond_init(&cond,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_cond_int is fail %s\n",strerror(ret));
    exit(-1);
  }
    
  

  pthread_t tid,uid;
  ret = pthread_create(&tid,NULL,producer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail %s\n",strerror(ret));
    exit(-1);
  }


  ret = pthread_create(&uid,NULL,consumer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail %s\n",strerror(ret));
    exit(-1);
  }

  pthread_join(uid,NULL);
  pthread_join(tid,NULL);

  if(ret != 0)
  {
    fprintf(stderr,"pthread_cond_destroy is fail %s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_mutex_destroy(&lock);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_destroy is fail %s\n",strerror(ret));
    exit(-1);
  }
  free(head);
  pthread_exit((void*)0);
}

void* producer(void* num)
{
  struct list* node;
  int ret;
  while(1)
  {
    pthread_mutex_lock(&lock);
    
    node = malloc(sizeof(struct list));
    node->data = rand()%100;
    node->next = head->next;
    head->next = node;
    printf("produce is %d\n",node->data);

    ret = pthread_mutex_unlock(&lock);
    if(ret != 0)
    {
      fprintf(stderr,"pthread_mutex_unlock is fail %s",strerror(ret));
      exit(-1);
    }
    ret = pthread_cond_signal(&cond);
    if(ret != 0)
    {
      fprintf(stderr,"pthead_cond_signal is fail %s",strerror(ret));
      exit(-1);
    }
    
    sleep(rand()%2);
  }
}
void* consumer(void* num)
{
  struct list* node;
  int ret;
  while(1)
  {
    ret = pthread_mutex_lock(&lock);
    
    
    while(head->next == NULL)
    {
      pthread_cond_wait(&cond,&lock);
    }
    
    node = head->next;
    head->next = node->next;
    printf("consumer is %d\n",node->data);
    free(node);
    node = NULL;

    ret = pthread_mutex_unlock(&lock);
    if(ret != 0)
    {
      fprintf(stderr,"pthread_mutex_unlock is fail %s\n",strerror(ret));
      exit(-1);
    }
    sleep(rand()%3);
  }
}

